package com.molichuxing.baselibrary.net;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.molichuxing.baselibrary.utils.LogUtils;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;

import java.io.File;
import java.io.IOException;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

/**
 * 网络请求管理
 * 对OkHttp请求进行封装
 */
public class OkHttpManager {

    private static OkHttpManager instance;
    private OkHttpClient mOkHttpClient;
    private Handler okHandler;
    private Gson mGson;

    public OkHttpManager() {
        mOkHttpClient = new OkHttpClient();
        okHandler = new Handler(Looper.getMainLooper());
        try {
//            mOkHttpClient.setConnectTimeout(90, TimeUnit.SECONDS);
            mOkHttpClient.setConnectTimeout(60, TimeUnit.SECONDS);
            mOkHttpClient.setWriteTimeout(60, TimeUnit.SECONDS);
            mOkHttpClient.setReadTimeout(60, TimeUnit.SECONDS);
//            mOkHttpClient.setReadTimeout();
        } catch (Exception e) {
            e.printStackTrace();
        }
        /**
         * cookie enabled
         * 只接受原始服务器的cookie
         */
//        mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
    }

    public static OkHttpManager getInstance() {
        if (instance == null) {
            synchronized (OkHttpManager.class) {
                if (instance == null) {
                    instance = new OkHttpManager();
                }
            }
        }
        return instance;
    }

    public Gson getmGson(){
        if(mGson==null){
            mGson = new Gson();
        }
        return mGson;
    }

    public void getNetJson(String url, ResultCallback resultCallback, ArrayList<Param> heads, String json) {
        if (heads == null) {
            heads = new ArrayList<Param>();
        }
        if (TextUtils.isEmpty(json)) {
            json = "";
        }
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        Request.Builder rBuilder = new Request.Builder();
        for (Param head : heads) {
            rBuilder.addHeader(head.key + "", head.value + "");
        }
        Request request = rBuilder.url(url).build();
        dealNet(request, resultCallback);
    }

    public void getNet(String url, ResultCallback resultCallback, ArrayList<Param> heads) {
        if (heads == null) {
            heads = new ArrayList<Param>();
        }
//        Request request = new Request.Builder()
//                .url(url)
//                .build();
        Request.Builder rBuilder = new Request.Builder();
        for (Param head : heads) {
            rBuilder.addHeader(head.key + "", head.value + "");
        }
        Request request = rBuilder.url(url).build();
        dealNet(request, resultCallback);
    }

    public void putNetJson(String url, ResultCallback resultCallback, String json, ArrayList<Param> heads) {
        if (heads == null) {
            heads = new ArrayList<Param>();
        }
        if (TextUtils.isEmpty(json)) {
            json = "";
        }
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        System.out.println(json);
        Request.Builder rBuilder = new Request.Builder();
        rBuilder.head();
        for (Param head : heads) {
            rBuilder.addHeader(head.key + "", head.value + "");
        }
        rBuilder.url(url)
                .put(body);
        Request request = rBuilder.build();
        dealNet(request, resultCallback);
    }

    public void postNetJson(String url, ResultCallback resultCallback, String json, ArrayList<Param> heads) {
        if (heads == null) {
            heads = new ArrayList<Param>();
        }
        if (TextUtils.isEmpty(json)) {
            json = "";
        }
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        System.out.println(json);
        Request.Builder rBuilder = new Request.Builder();
        rBuilder.head();
        for (Param head : heads) {
            rBuilder.addHeader(head.key + "", head.value + "");
        }
        rBuilder.url(url)
                .post(body);
        Request request = rBuilder.build();
        dealNet(request, resultCallback);
    }

    public void postNet(String url, ResultCallback resultCallback, ArrayList<Param> param, ArrayList<Param> heads) {
        if (param == null) {
            param = new ArrayList<Param>();
        }
        if (heads == null) {
            heads = new ArrayList<Param>();
        }
        FormEncodingBuilder formEncodingBuilder = new FormEncodingBuilder();
        for (Param p : param) {
            formEncodingBuilder.add(p.key, p.value);
        }
        RequestBody requestBody = formEncodingBuilder.build();
        Request.Builder rBuilder = new Request.Builder();
        rBuilder.head();
        for (Param head : heads) {
            rBuilder.addHeader(head.key + "", head.value + "");
        }
        rBuilder.url(url)
                .post(requestBody);
        Request request = rBuilder.build();
        dealNet(request, resultCallback);
    }

    public void upFileNet(String url, ResultCallback resultCallback, File[] files,
                          String[] fileKeys, ArrayList<Param> param) {
        Request request = buildMultipartFormRequest(url, files, fileKeys, param);

        dealNet(request, resultCallback);
    }

    public void upFileNetJson(String url, ResultCallback resultCallback, File[] files,
                              String[] fileKeys, String json) {
        Request request = buildMultipartFormRequestJson(url, files, fileKeys, json);
        System.out.println(json);
        dealNet(request, resultCallback);
    }

    private Request buildMultipartFormRequestJson(String url, File[] files, String[] fileKeys,
                                                  String json) {
        MultipartBuilder builder = new MultipartBuilder()
                .type(MultipartBuilder.FORM);

        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        builder.addPart(body);
        if (files != null) {
            RequestBody fileBody = null;
            for (int i = 0; i < files.length; i++) {
                File file = files[i];
                String fileName = file.getName();
                fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
                //根据文件名设置contentType
                builder.addPart(Headers.of("Content-Disposition",
                        "form-data; name=\"" + fileKeys[i] + "\"; filename=\"" + fileName + "\""),
                        fileBody);
            }
        }

        RequestBody requestBody = builder.build();
        Request.Builder rBuider = new Request.Builder();

        rBuider.url(url)
                .post(requestBody);

        return rBuider.build();
    }

    private void dealNet(final Request request, final ResultCallback resultCallback) {
        LogUtils.i("dove", "请求url:" + request.urlString() + "\n" + request.headers());
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(final Request request, final IOException e) {
                okHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        resultCallback.onFailed(request, e);
                    }
                });
            }
            @Override
            public void onResponse(final Response response) {
                String str = "";
                try {
                    str = response.body().string();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                final String finalStr = str;
                okHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        LogUtils.i("dove","请求url:" + request.urlString()+"请求返回-"+finalStr);
                        resultCallback.onSuccess(finalStr);
                    }
                });
            }
        });
    }

    private Request buildMultipartFormRequest(String url, File[] files, String[] fileKeys,
                                              ArrayList<Param> params) {
        params = validateParam(params);

        MultipartBuilder builder = new MultipartBuilder()
                .type(MultipartBuilder.FORM);

        for (Param param : params) {
            builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + param.key + "\""),
                    RequestBody.create(null, param.value));
        }
        if (files != null) {
            RequestBody fileBody = null;
            for (int i = 0; i < files.length; i++) {
                File file = files[i];
                String fileName = file.getName();
                fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
                //根据文件名设置contentType
                builder.addPart(Headers.of("Content-Disposition",
                        "form-data; name=\"" + fileKeys[i] + "\"; filename=\"" + fileName + "\""),
                        fileBody);
            }
        }

        RequestBody requestBody = builder.build();
        Request.Builder rBuider = new Request.Builder();

        rBuider.url(url)
                .post(requestBody);

        return rBuider.build();
    }

    private ArrayList<Param> validateParam(ArrayList<Param> params) {
        if (params == null)
            return new ArrayList<Param>();
        else return params;
    }

    private String guessMimeType(String path) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(path);
        if (contentTypeFor == null) {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;
    }

    public static abstract class ResultCallback {
        public abstract void onFailed(Request request, Exception e);

        public abstract void onSuccess(String response);
    }

    public static class Param {
        String key;
        String value;

        public Param() {
        }

        public Param(String key, String value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public String toString() {
            return "Param{" +
                    "key='" + key + '\'' +
                    ", value='" + value + '\'' +
                    '}';
        }
    }
}
